home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 08 - 1992 / 08.02 Jun 92 / Generic Virus Detection / Dynamic.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-26  |  7.2 KB  |  205 lines  |  [TEXT/MPS ]

  1. /* Dynamic.c — Functions for dynamic k-approximate virus infection detection.
  2.     Copyright © 1992 by William H. Hsu.
  3.     Thanks to John Norstad and Ephraim Vishniac for help and comments.  Portions of this code are based on [Morton 90], which appears in the May 1990 issue of MacTutor.  Reused with permission.  You may copy, alter, use, and distribute all code listed here if you leave the file unchanged up to this line.
  4.     Think C version.
  5.  
  6.     Notes:
  7.     •    A main advantage of this code, as explained in the “Methods and History” section, is that its effectiveness is not diminished by its availability.  No matter how many potential virus authors read it, the algorithm will remain equally effective against circumvention.
  8.     •    To use this code in your programs:
  9.     — it will be necessary to obtain non-functional
  10. but significant (larger than 300 bytes) resource segments from the virus you are trying to detect
  11.     - using a resource editor, insert the viral data under an unused type, such as 'VDAT', used in the code below
  12.     - this will render the virus code inactive and most likely invisible to conventional (Class 2 and 3) detection programs; as and added security measure, you may wish to include only code segments above 300 bytes (or a similar threshold length) to ensure that the virus is crippled
  13.     - both these C routines and the Boyer-Moore routines require an expanded 512K Mac or later (specifically, System 3.2 or later); they have been fully tested on the SE, II, and IIcx        
  14.     -    this function should be run upon first launching your application, or, if it is an operating system utility, during a “dormant” or idle period
  15.     - the code below assumes that the VDAT resource contains all 5 segments of nVIR A; change this accordingly by adding additional virus types (under a name other than the original infected type) */
  16.  
  17. #include "dec.h"
  18.  
  19. FILE *my_file;
  20. void dynamic()
  21. {
  22.   char m[MAXSIZE];
  23.   int pattern_length, index;
  24.   MATRIX table;
  25.   register Handle rsrc;
  26.   short resCount;
  27.   ToolBoxInit();
  28.   CurResFile();
  29.   resCount = Count1Resources ('VDAT');    
  30.     /* how many of this type are there? */
  31.   open_file (&my_file, WRITE_MODE);
  32. #ifdef _REPORT    /* developer debug flag */
  33.   printf("Searching for <<virus name>>:\n\n");
  34.   fprintf(my_file, "Searching for <<virus             name>>:\n\n");
  35. #endif
  36.   while (resCount) /* loop down to 1 */
  37.   {
  38.         if (resCount == 3)
  39.         {
  40.         printf("\nSearching for <<virus                     name>>:\n\n");
  41.         fprintf(my_file, "\nSearching for <<virus                 name>>:\n\n");
  42.         }    
  43.    rsrc = Get1IndResource ('VDAT', resCount);    
  44.     /* get the resource's handle, but don't load             it */
  45.     index = SizeResource (rsrc);
  46.     HLock (rsrc);
  47.     /* load next virus segment */
  48.     pattern_length = copy_array (*rsrc, m,             &index);
  49. #ifdef _REPORT
  50.   printf("Next virus segment loaded (length         %d).  Resources left to scan: %d\n",             pattern_length, resCount);
  51.     fprintf(my_file, "Next virus segment loaded         (length %d).  Resources left to scan:             %d\n", pattern_length, resCount);
  52. #endif
  53.     HUnlock (rsrc);
  54.     initialize(&table, pattern_length+1);
  55.     vResCheck('nVRB', m, pattern_length, table, NO_REPORT);
  56. #    ifdef _REPORT
  57.             printf("\n");
  58.             fprintf(my_file, "\n");
  59. #    endif
  60.     vResCheck('nVRA', m, pattern_length, table,         NO_REPORT);
  61. #    ifdef _REPORT
  62.             printf("\n\n");
  63.             fprintf(my_file, "\n\n");
  64. #    endif
  65.     --resCount;
  66.   }   
  67.   fclose(my_file);
  68. }
  69.  
  70. void initialize(table, length)
  71. MATRIX *table;
  72. int length;
  73. {
  74.   allocate_table(table, length);
  75.   clear_table(*table, length);
  76. }
  77.  
  78. void allocate_table(table, size)
  79. MATRIX *table;
  80. int size;
  81. {
  82.   int i;
  83.   *table = (MATRIX)calloc(size, (size_t)sizeof(long *));
  84.   for (i = 0; i < size; i++)
  85.     (*table)[i] = (long *)calloc(2,                         (size_t)sizeof(long));
  86. }
  87.  
  88. void clear_table(table, length)
  89. MATRIX table;
  90. int length;
  91. {
  92.   int i;
  93.   for (i = 0; i <= length; i++)
  94.     table[i][0] = (long)UNIT*i;
  95. }
  96.  
  97. /* vResCheck - Perform dynamic string search on all resources of a specified type in the current application. */
  98. void vResCheck (type, m, pattern_length, table, report)
  99.     register ResType type;    /* INPUT: type of         resource to sum */
  100.     char m[MAXSIZE];
  101.     int pattern_length;
  102.     MATRIX table;
  103.     register short report;
  104. /* INPUT: >0 => report errors with debugger */
  105.     {
  106.         register short resCount;    
  107.             /* number of resources of this type */
  108.         register Handle rsrc;    /* resource to check */
  109.         register short oldResFile;
  110.             /* for preserving current resource file */
  111.         register Boolean oldResLoad;
  112.             /* for preserving "ResLoad" flag */
  113.         Boolean found;
  114.         char n[MAXSIZE];
  115.         int text_length, local_count = 1;
  116.         int index;
  117.             
  118.     /* Switch to the application's resource file.  Note that all resource calls from here on are the "one deep" calls from Inside Mac, Volume
  119. IV. */
  120.     oldResFile = CurResFile();
  121.     /* remember initial resource file */
  122.     oldResLoad = ResLoad;    /* remember "ResLoad" state */
  123.     resCount = Count1Resources (type);    
  124.         /* how many of this type are there? */
  125.   if (report)
  126.   {
  127.         fprintf(my_file, "Text string ");
  128.         printf("Text string ");
  129.   }
  130.     while (resCount)    /* loop down to 1 */
  131.     {    /* get the resource's handle, but don't load it */
  132.         rsrc = Get1IndResource (type, resCount);
  133.             /* see if it's already in memory */
  134.         if (!rsrc)    /* not available? */
  135.         {
  136.             if (report > 0)        /* debugging flag */
  137.                 DebugStr ("\pResource not available!");
  138.             goto EXIT;
  139.         }
  140.         else
  141.         {
  142.             index = SizeResource (rsrc);
  143.             HLock (rsrc);
  144.             found = FALSE;
  145.             while ((text_length = copy_array(*rsrc, n,                 &index)) && (!found))
  146.             {
  147.                 fprintf (my_file, "%d… ", local_count);
  148.                 printf ("%d… ", local_count);
  149.                 local_count++;
  150.                 clear_table (table, pattern_length);
  151.                 if (pattern_length <= text_length)
  152.                 {
  153.                     if (compare (m, n, pattern_length,                         text_length, table))
  154.                       found = TRUE;
  155.                 }
  156.             }
  157.             HUnlock (rsrc);
  158.         }
  159.         --resCount;    /* get next index number */
  160.     }    /* end of loop through resources */
  161.     
  162.     EXIT: /* goto here on tampering or error */
  163.         UseResFile (oldResFile);    /* restore original resource file */
  164.         SetResLoad (oldResLoad);    /* restore original loading state */
  165.     }    /* end of vResCheck() */
  166.  
  167. /* compare: the actual dynamic programming algorithm, modified to a level of padding tolerance defined by THRESHOLD */
  168. char compare(p, t, pattern_length, text_length, table)
  169. char p[], t[];
  170. int pattern_length, text_length;
  171. MATRIX table;
  172.   long value1, value2, value3;
  173.   int i, j, flip, beep;
  174.   flip = TRUE;
  175.   for (j = 1; j <= text_length; j++)
  176.   {
  177.     table[0][flip] = 0;
  178.     for (i = 1; i <= pattern_length; i++)
  179.     {
  180.             if (p[i-1] == t[j-1]) /* initialize */
  181.         value1 = table[i-1][!flip];
  182.       else
  183.         value1 = (table[i-1][!flip])+UNIT;
  184.       value2 = (table[i-1][flip])+UNIT;
  185.                 /* UNIT: the orginal algorithm uses this                 weight for all variations in the text */
  186.       value3 = (table[i][!flip])+EPSILON;
  187.                 /* EPSILON: small weighted "distance" --                as opposed to the single unit */
  188.       table[i][flip] = MIN3(value1, value2,                 value3);    /* see discussion of dynamic */
  189.     }
  190.     if (table[pattern_length][flip] <=                     THRESHOLD)
  191.     {
  192.             if (report)
  193.             {
  194.       printf("%ld-approximate match found.\n",                     table[pattern_length][flip]);
  195.       fprintf(my_file, "%ld-approximate match                     found.\n", table[pattern_length][flip]);
  196.             }
  197.             return (TRUE);
  198.     }
  199.     flip = !(flip);        /* only an O(2m)-sized             array is needed to simulate a "matrix",             because only 2 columns are used */
  200.   }
  201.   return (FALSE);
  202. }
  203.  
  204.